global class defensio {
	global class defResponse{
		string status;
		boolean spam;
		string signature;
		decimal spaminess;
		string message;
		string apiversion;
	}

	global class defStatsResponse{
		//this is a container class to handle a get-stats result
		string message;
		string status;
		decimal accuracy;
		string learningstatus;
		boolean learning;
		string apiversion;
		integer falsenegatives;
		integer falsepositives;
		integer ham;
		integer spam;		
	}	
	public void validateKey(){	
		//set up our request object
		httprequest req = new httprequest();
		
		//and paramenters
		List<global__c> apikeyrequest = [select Value__c from Global__c where Name = 'defensiokey' limit 1];
		string apikey = apikeyrequest[0].Value__c;
		List<global__c> ownerurlrequest = [select Value__c from Global__c where Name = 'defensiourl' limit 1];
		string ownerurl = ownerurlrequest[0].Value__c;
		string apiurl = 'http://api.defensio.com/app/1.2/';
		string action = 'validate-key/';
		string responsetype = 'xml';
		string endpoint = apiurl + action + apikey + '.' + responsetype + '?owner-url=' + ownerurl;
		system.debug(endpoint);
		
		//do the request
		req.setEndpoint(endpoint);
		req.setMethod('GET');
		http http = new http();
		httpresponse validateResponse = http.send(req);
		system.debug(validateResponse.getBody());
	}
	
	static testMethod void testVerifyKey(){
		defensio def = new defensio();
		def.validateKey();
	}
	
	public boolean auditComment(string sentfromname, string sentfromemail, string bodytext){
		//set up our request object
		httprequest req = new httprequest();
		
		//and paramenters
		List<global__c> apikeyrequest = [select Value__c from Global__c where Name = 'defensiokey' limit 1];
		string apikey = apikeyrequest[0].Value__c;
		List<global__c> ownerurlrequest = [select Value__c from Global__c where Name = 'defensiourl' limit 1];
		string ownerurl = ownerurlrequest[0].Value__c;
		defensio d = new defensio();
		string articleDate = d.getDate();
		
		string commentAuthor = encodingutil.urlencode(sentfromname,'UTF-8'); 
		string commentAuthorEmail = encodingutil.urlencode(sentfromemail,'UTF-8');
		string commentContent = encodingutil.urlencode(bodytext,'UTF-8');
		string apiurl = 'http://api.defensio.com/app/1.1/';
		string action = 'audit-comment/';
		string responsetype = 'xml';
		string body = 'comment-author=' + commentAuthor + '&comment-author-email=' + commentAuthorEmail + '&owner-url=' + ownerurl + '&article-date=' + articleDate + '&comment-content=' + commentContent + '&user-ip=64.25.87.42' + '&comment-type=other';
		string endpoint = apiurl + action + apikey + '.' + responsetype;
		system.debug(endpoint);
		
		//do the request
		req.setEndpoint(endpoint);
		Map<string, string> headers = new Map<string, string>();
		headers.put('content-length', '0');
		req.setHeader('content-length', headers.get('content-length'));
		req.setMethod('POST');
		req.setBody(body);
		system.debug(body);
		http http = new http();
		httpresponse auditCommentResponse = http.send(req);
		string response = auditCommentResponse.getBody();
		system.debug('\n\n---Response: ' + response + '---\n\n');

		defensio def = new defensio();
		defResponse resp = def.parseDefensioResponse(response);

		system.debug('defResponse: ' + resp);
		def.insertDefinition(resp.signature, resp.spam, resp.spaminess, resp.message, resp.apiversion, resp.status, bodytext);
		return resp.spam;
	}
	
	WebService static string reportFalseNegative(string sig){
		//set up our request object
		httprequest req = new httprequest();
		
		//and paramenters
		List<global__c> apikeyrequest = [select Value__c from Global__c where Name = 'defensiokey' limit 1];
		string apikey = apikeyrequest[0].Value__c;
		List<global__c> ownerurlrequest = [select Value__c from Global__c where Name = 'defensiourl' limit 1];
		string ownerurl = ownerurlrequest[0].Value__c;
		
		string apiurl = 'http://api.defensio.com/app/1.1/';
		string action = 'report-false-negatives/';
		string responsetype = 'xml';
		string body = 'owner-url=' + ownerurl +'&signatures=' + sig;
		string endpoint = apiurl + action + apikey + '.' + responsetype;
		system.debug(endpoint);
		
		//do the request
		req.setEndpoint(endpoint);
		Map<string, string> headers = new Map<string, string>();
		headers.put('content-length', '0');
		req.setHeader('content-length', headers.get('content-length'));
		req.setMethod('POST');
		req.setBody(body);
		system.debug(body);
		http http = new http();
		httpresponse auditCommentResponse = http.send(req);
		string response = auditCommentResponse.getBody();
		system.debug('\n\n---Response: ' + response + '---\n\n');
		
		//now we set the defensio__c object to trained = true
		defensio__c[] d;
		d = [select id, trained__c from defensio__c where name = :sig limit 1];
		d[0].trained__c = true;
		update d;		
		return response;	
	}

	WebService static string reportFalsePositive(string sig){
		//set up our request object
		httprequest req = new httprequest();
		
		//and paramenters
		List<global__c> apikeyrequest = [select Value__c from Global__c where Name = 'defensiokey' limit 1];
		string apikey = apikeyrequest[0].Value__c;
		List<global__c> ownerurlrequest = [select Value__c from Global__c where Name = 'defensiourl' limit 1];
		string ownerurl = ownerurlrequest[0].Value__c;
		
		string apiurl = 'http://api.defensio.com/app/1.1/';
		string action = 'report-false-positives/';
		string responsetype = 'xml';
		string body = 'owner-url=' + ownerurl +'&signatures=' + sig;
		string endpoint = apiurl + action + apikey + '.' + responsetype;
		system.debug(endpoint);
		
		//do the request
		req.setEndpoint(endpoint);
		Map<string, string> headers = new Map<string, string>();
		headers.put('content-length', '0');
		req.setHeader('content-length', headers.get('content-length'));
		req.setMethod('POST');
		req.setBody(body);
		system.debug(body);
		http http = new http();
		httpresponse auditCommentResponse = http.send(req);
		string response = auditCommentResponse.getBody();
		system.debug('\n\n---Response: ' + response + '---\n\n');
		
		//now we set the defensio__c object to trained = true
		defensio__c[] d;
		d = [select id, trained__c from defensio__c where name = :sig limit 1];
		d[0].trained__c = true;
		update d;
		
		return response;	
	}	
	public string getDate(){
		//get a datetime
		datetime rawdate = system.now();
		string msgday = rawdate.day().format();
		string msgmonth = rawdate.month().format();
		string msgyear = rawdate.year().format().replace(',','');
		
		//make sure we have 2 digit month and day
		if (msgday.length() < 2){
			msgday = '0' + msgday;
		}
		if (msgmonth.length() < 2){
			msgmonth = '0' + msgmonth;
		}
		string msgdate = msgyear + '/' + msgmonth + '/' + msgday;
		system.debug('\n\nDate: ' + msgdate);
		return msgdate;
	}	
	
	public void insertDefinition(string sig, boolean spam, decimal spaminess, string message, string api, string status, string comment){
		//create our defensio record sobject
		defensio__c def = new defensio__c(name = sig, spam__c = spam, spaminess__c = spaminess, message__c = message, api__c = api, status__c = status, comment__c = comment);
		insert def;
	}
	
	public defResponse parseDefensioResponse(string stream){
		XmlStreamReader reader = new XmlStreamReader(stream);
		
		defResponse resp = new defResponse();
		
		while(reader.hasNext()) {
			//  Start at the beginning of the book and make sure that it is a book
         	//system.debug('getLocalName: ' + reader.getLocalName());
         	
         	if (reader.getEventType() == XmlTag.START_ELEMENT) {
	            if ('status' == reader.getLocalName()){
	               	reader.next();
	               	if (reader.getEventType() != XmlTag.END_ELEMENT){
		            	system.debug('status: ' + reader.getText());
		            	resp.status = reader.getText();
	               	}
	            }else if ('spam' == reader.getLocalName()){
	            	reader.next();
	            	if (reader.getEventType() != XmlTag.END_ELEMENT){
		            	system.debug('spam: ' + reader.getText());
		            	boolean spamresult;
		            	if (reader.getText() == 'true'){
		            		spamresult = true;
		            	}else{
		            		spamresult = false;
		            	}
		            	resp.spam = spamresult;
	            	}
	            }else if ('spaminess' == reader.getLocalName()){
	            	reader.next();
	            	if (reader.getEventType() != XmlTag.END_ELEMENT){
		            	system.debug('spaminess: ' + reader.getText());
		            	resp.spaminess = decimal.valueof(reader.getText());
	            	}
	            }else if ('message' == reader.getLocalName()){
	            	reader.next();
	            	if (reader.getEventType() != XmlTag.END_ELEMENT){
		            	system.debug('message: ' + reader.getText());
		            	resp.message = reader.getText();
	            	}
	            }else if ('api-version' == reader.getLocalName()){
	            	reader.next();
	            	if (reader.getEventType() != XmlTag.END_ELEMENT){
		            	system.debug('apiversion: ' + reader.getText());
		            	resp.apiversion = reader.getText();
	            	}
	            }else if ('signature' == reader.getLocalName()){
	            	reader.next();
	            	if (reader.getEventType() != XmlTag.END_ELEMENT){
		            	system.debug('signature: ' + reader.getText());
		            	resp.signature = reader.getText();
	            	}
	            }
         	}
         	reader.next();
		}
		return resp;
	}
            
	webservice static string getStats(){
		//set up our request object
		httprequest req = new httprequest();
		
		//and paramenters
		List<global__c> apikeyrequest = [select Value__c from Global__c where Name = 'defensiokey' limit 1];
		string apikey = apikeyrequest[0].Value__c;
		List<global__c> ownerurlrequest = [select Value__c from Global__c where Name = 'defensiourl' limit 1];
		string ownerurl = ownerurlrequest[0].Value__c;
		
		string apiurl = 'http://api.defensio.com/app/1.1/';
		string action = 'get-stats/';
		string responsetype = 'yaml';
		string body = 'owner-url=' + ownerurl;
		string endpoint = apiurl + action + apikey + '.' + responsetype;
		system.debug(endpoint);
		
		//do the request
		req.setEndpoint(endpoint);
		Map<string, string> headers = new Map<string, string>();
		headers.put('content-length', '0');
		req.setHeader('content-length', headers.get('content-length'));
		req.setMethod('POST');
		req.setBody(body);
		system.debug(body);
		http http = new http();
		httpresponse getStatsResponse = http.send(req);
		string response = getStatsResponse.getBody();
		system.debug('\n\n---Response: ' + response + '---\n\n');		
		return response;
	}
	
	static testMethod void testInsertDefinitio(){
		//create good data
		string sig = 'lka;jsdpoiwqmef3898909';
		boolean spam = true;
		decimal spaminess = 0.9932;
		string message = 'Spam check OK';
		string api = '1.2';
		string status = 'success';
		string comment = 'this was a test message';
		
		//insert properly formatted record
		defensio def = new defensio();
		def.insertDefinition(sig, spam, spaminess,message,api,status,comment);
	}
	
	static testMethod void testAuditComment(){ 
		//set up the comment to be tested
		string sentfrom = 'Paul McGurn';
		string bodytext = 'Here is my test post.  Hopefully this doesn\'t get flagged.';
		string fromemail = 'pmcgurn@logmein.com';
		defensio def = new defensio();
		boolean spamresult = def.auditComment(sentfrom, fromemail, bodytext);
	}	
	
	static testMethod void testReportFalsePositive(){
		string sig = ';alksmdf[pimadfd';
		defensio.reportFalsePositive(sig);
	}
	
	static testMethod void testReportFalseNegative(){
		string sig = ';alksmdf[pimadfd';
		defensio.reportFalseNegative(sig);
	}
	
	static testMethod void testGetStats(){
		defensio.getStats();
	}	
	
	static testMethod void testParseResponse(){
		string xmlstring = '<?xml version="1.0" encoding="UTF-8"?><defensio-result><message>A status message</message><signature>opiasdfmdfa</signature><status>success</status><spam>true</spam><spaminess>0.2</spaminess><api-version>1.2</api-version></defensio-result>';
		defensio d = new defensio();
		d.parseDefensioResponse(xmlstring);
	}
	
	static testMethod void testGetDate(){
		defensio def = new defensio();
		def.getDate();
	}
}